//Aufgabe3 - Half-round-trip latency (MPI)

#include <iostream>
#include <mpi.h>
#include <unistd.h>
#include <sys/time.h>

using namespace std;

typedef struct timeval timeVal;

const int maxMessageSize = 1048576;

void doWork(int size, int rank);
unsigned long calcRuntime(timeVal start, timeVal end);

/*
 * MAIN()
 */
int main(int argc, char** argv){
 
 int size, rank;

 MPI_Init(&argc,&argv);

 MPI_Comm_rank(MPI_COMM_WORLD,&rank);
 MPI_Comm_size(MPI_COMM_WORLD,&size);
 
 doWork(size, rank);

 MPI_Finalize();
 return 0;
}

/*doWork*/
void doWork(int size,int rank){
	float* oBuffer = new float[maxMessageSize];
	float* iBuffer = new float[maxMessageSize];

	MPI_Status status;
	timeVal start,end;
	unsigned long rtt = 0;

	for(int i = 1; i <= maxMessageSize; i*=2){
		for(int j = 0; j < 10 ; j++){
		if(rank == 0){
			rtt = 0; 
			gettimeofday(&start,NULL);

			MPI_Send(oBuffer,i,MPI_FLOAT,1,0,MPI_COMM_WORLD);
			MPI_Recv(iBuffer,i,MPI_FLOAT,1,0,MPI_COMM_WORLD,&status);

			gettimeofday(&end,NULL);
		
			rtt = calcRuntime(start,end);
			cout << "Messagesize: " << i << " = " << i*sizeof(float) <<" Byte "<<" RTT[us]: " << rtt << " HRTT[us]: " << rtt/2 << endl;
		}else if(rank == 1){
			MPI_Recv(iBuffer,i,MPI_FLOAT,0,0,MPI_COMM_WORLD,&status);			
			MPI_Send(oBuffer,i,MPI_FLOAT,0,0,MPI_COMM_WORLD);
		}else{
			break;
		}	
		}
	}	

	delete [] oBuffer;
	delete [] iBuffer;
}

/*calcRuntime*/
unsigned long calcRuntime(timeVal start, timeVal end)
{
	/* calc time difference */
	timeVal diff;
	diff.tv_sec = end.tv_sec - start.tv_sec;
	if (start.tv_usec > end.tv_usec){
		diff.tv_usec = (1e6 - end.tv_usec) + start.tv_usec;
	}else{
		diff.tv_usec = end.tv_usec - start.tv_usec;
	}

	return diff.tv_sec * 1e6 + diff.tv_usec;
}
